﻿/*=============================================================================
* File Name : Vector3.cpp                         Ver : 1.00  Date : 2009-3-17
*
* Description :
*
*       3Dベクトル計算　ソース
*
* Author : 土田　悠貴.
*============================================================================*/
#include "Vector3.h"
#include "Math.h"
#include "Vector2.h"
#include "Vector4.h"
#include "Matrix3.h"
#include "Matrix4.h"

namespace tglib
{

/*===========================================================================*/
/**
 * コンストラクタ．
 */
Vector3::Vector3() : x( 0.0f ), y( 0.0f ), z( 0.0f )
{}

/*===========================================================================*/
/**
 * コンストラクタ．
 *
 * @param [in]     X　X座標．
 * @param [in]     Y　Y座標．
 * @param [in]     Z　Z座標．
 */
Vector3::Vector3( float X, float Y, float Z ) :
	x( X ), y( Y ), z( Z )
{}

/*===========================================================================*/
/**
 * コンストラクタ．
 *
 * @param [in]     v2　2Dベクトル．
 * @param [in]     Z　 Z座標．
 */
Vector3::Vector3( const Vector2& v2, float Z ) :
	x( v2.x ), y( v2.y ), z( Z )
{}

/*===========================================================================*/
/**
 * コンストラクタ．
 *
 * @param [in]     v4　四次元ベクトル．
 */
Vector3::Vector3( const Vector4& v4 ) :
	x( v4.x ), y( v4.y ), z( v4.z )
{}

/*===========================================================================*/
/**
 * コンストラクタ．
 *
 * @param [in]     p　配列のポインタ．
 */
Vector3::Vector3( const float* p ) :
	x( p[0] ), y( p[1] ), z( p[2] )
{}

/*===========================================================================*/
/**
 * 正規化．
 *
 * @return 正規化したベクトル．
 */
Vector3& Vector3::normalize()
{
	float len;

	if( ( len = length() ) != 0 ){
		(*this) /= len;
	}

	return *this;
}

/*===========================================================================*/
/**
 * 正規化したベクトルを取得する．
 *
 * @return 正規化したベクトル．
 */
Vector3 Vector3::getNormalized() const
{
	Vector3	result( *this );

	return result.normalize();
}

/*===========================================================================*/
/**
 * 長さを求める．
 *
 * @return 長さ ．
 */
float Vector3::length() const
{
	return Math::Sqrt( lengthSq() );
}

/*===========================================================================*/
/**
 * 長さを求める (２乗和のみ）．
 *
 * @return 長さ(２乗和）．
 */
float Vector3::lengthSq() const
{
	return ( x * x + y * y + z * z );
}

/*===========================================================================*/
/**
 * 距離を求める．
 *
 * @param [in]  V 3Dベクトル ．
 * @return 距離 ．
 */
float Vector3::distance( const Vector3& V ) const
{
	Vector3 result;

	result = *this - V;

	return ( result.length() );
}

/*===========================================================================*/
/**
 * 内積を求める．
 *
 * @param [in]  V 3Dベクトル ．
 * @return 内積 ．
 */
float Vector3::dot( const Vector3& V ) const
{
	return ( x * V.x + y * V.y + z * V.z );
}


/*===========================================================================*/
/**
 * 外積を求める．
 *
 * @param [in]  V 3Dベクトル ．
 * @return 外積 ．
 */
Vector3 Vector3::cross( const Vector3& V ) const
{
	return Vector3( y * V.z - z * V.y, z * V.x - x * V.z, x * V.y - y * V.x );
}

/*===========================================================================*/
/**
 * 小さい要素を求める．
 *
 * @param [in]  V 3Dベクトル ．
 * @return 小さい要素 ．
 */
Vector3 Vector3::minimize( const Vector3& V	) const
{
	Vector3 result;

	result.x = Math::MIN( x, V.x );
	result.y = Math::MIN( y, V.y );
	result.z = Math::MIN( z, V.z );

	return result;
}

/*===========================================================================*/
/**
 * 大きい要素を求める．
 *
 * @param [in]  V 3Dベクトル ．
 * @return 大きい要素 ．
 */
Vector3 Vector3::maximize( const Vector3& V ) const
{
	Vector3 result;

	result.x = Math::MAX( x, V.x );
	result.y = Math::MAX( y, V.y );
	result.z = Math::MAX( z, V.z );

	return result;
}

/*===========================================================================*/
/**
 * 線形補間を行う．
 *
 * @param [in]  min 最小値 ．
 * @param [in]  max 最大値 ．
 * @param [in]  t 補間地(0.0～1.0) ．
 * @return 補間した3Dベクトル ．
 */
Vector3& Vector3::lerp( const Vector3& min, const Vector3& max, float t )
{
	x = Math::LERP( t, min.x, max.x );
	y = Math::LERP( t, min.y, max.y );
	z = Math::LERP( t, min.z, max.z );

	return *this;
}

/*===========================================================================*/
/**
 * 二次補間を行う．
 *
 * @param [in]  v1 補間要素3Dベクトル.
 * @param [in]  v2 補間要素3Dベクトル.
 * @param [in]  v3 3Dベクトル.
 * @param [in]  t 補間値( 0.0f～1.0f ).
 * @return 補間した3Dベクトル ．
 */
Vector3& Vector3::quadratic(const Vector3& v1, const Vector3& v2, const Vector3& v3, float t)
{
	x = Math::QUADRATIC( t, v1.x, v2.x, v3.x );
	y = Math::QUADRATIC( t, v1.y, v2.y, v3.y );
	z = Math::QUADRATIC( t, v1.z, v2.z, v3.z );

	return *this;
}

/*===========================================================================*/
/**
 * 反射ベクトルを求める ．
 *
 * @param [in]  N 法線ベクトル ．
 * @return 反射ベクトル ．
 */
Vector3 Vector3::reflect( const Vector3& N ) const
{
	Vector3	result;

	Vector3	v( -(*this) );

	Vector3	t( N * ( v.dot( N ) * 2.0f ) );

	result = t + *this;

	return result;
}

/*===========================================================================*/
/**
 * 屈折ベクトルを求める．
 *
 * @param [in]  N 　法線ベクトル ．
 * @param [in]  Eta 屈折比率 ．
 * @return 屈折ベクトル ．
 */
Vector3 Vector3::refract( const Vector3& N, float Eta ) const
{
	Vector3 result;

	Vector3 T1( -(*this) );
	float cosI  = T1.dot( N );
	float cosT2 = 1.0f - Eta * Eta * ( 1.0f - cosI * cosI );

	if( cosT2 <= 0.0f ){
		result.x = 0.0f;
		result.y = 0.0f;
	} else {
		T1 = (*this) * Eta;
		Vector3 T2( N * ( Eta * cosI - Math::Sqrt( Math::ABS( cosT2 ) ) ) );
		result = T1 + T2;
	}

	return result;
}

/*===========================================================================*/
/**
 * ２つベクトルのなす角度を求める．
 *
 * @param [in]  V　3Dベクトル ．
 * @return 角度 ．
 */
float Vector3::degree( const Vector3& V ) const
{
	float cos_theat = ( dot( V ) / ( length() * V.length() ) );

	float angle = Math::Acos( Math::CLAMP( cos_theat, -1.0f, 1.0f ) );

	return angle;
}

/*===========================================================================*/
/**
 * ヨーを求める．
 *
 * @return ヨー ．
 */
float Vector3::getYaw() const
{
	float len;

	// ベクトルの長さを求める
	if( ( len = length() ) == 0 ){
		// 長さが０の場合は０にする
		return 0.0f;
	}

	// ベクトルを正規化する
	float X = x / len;
	float Z = z / len;

	// ヨーの計算を行う
	return Math::Atan( X, Z );
}

/*===========================================================================*/
/**
 * ピッチを求める．
 *
 * @return ピッチ．
 */
float Vector3::getPitch() const
{
	float len;

	// ベクトルの長さを求める
	if( ( len = length() ) == 0 ){
		// 長さが０の場合は０にする
		return 0.0f;
	}

	// ベクトルを正規化する
	float Y = y / len;

	// ヨーの計算を行う
	return Math::DegreeNormalize( Math::Asin( -Y ) );
}

/*===========================================================================*/
/**
 * ピッチ・ヨーからベクトルを求める．
 *
 * @param [in]  picth　ピッチ．
 * @param [in]  yow　  ヨー．
 * @return 3Dベクトル．
 */
Vector3& Vector3::fromPitchYaw( float picth, float yow )
{
	x = Math::Cos( picth ) * Math::Sin( yow );
	y = -( Math::Sin( picth ) );
	z = Math::Cos( picth ) * Math::Cos( yow );

	return *this;
}

/*===========================================================================*/
/**
 * 法線ベクトルを求める．
 *
 * @param [in]  V1　三角形の頂点座標．
 * @param [in]  V2　三角形の頂点座標．
 * @return 法線ベクトル．
 */
Vector3 Vector3::calculateNormal( const Vector3& V1, const Vector3& V2 ) const
{
	Vector3 n = *this - V1;
	Vector3 m = V1    - V2;

	Vector3 result = n.cross( m );

	result.normalize();

	return result;
}

/*===========================================================================*/
/**
 * 直線の方程式の計算を行う．
 *
 * @param [in]  V1　3Dベクトル．
 * @param [in]  V2　3Dベクトル．
 * @param [in]  t　 係数．
 * @return 結果．
 */
Vector3& Vector3::linearEquation( const Vector3& V1, const Vector3& V2, float t )
{
	x = V1.x * t + V2.x;
	y = V1.y * t + V2.y;
	z = V1.z * t + V2.z;

	return *this;
}

/*===========================================================================*/
/**
 * (float*型)キャスト演算子オーバーロード．
 *
 * @return   型変換をしたXYZ成分．
 */
Vector3::operator float* ()
{
	return reinterpret_cast<float*>( XYZ );
}

/*===========================================================================*/
/**
 * (const float*型)キャスト演算子オーバーロード．
 *
 * @return   型変換をしたXYZ成分．
 */
Vector3::operator const float* ()
{
	return reinterpret_cast<const float*>( XYZ );
}

/*===========================================================================*/
/**
 * (+)単項演算子オーバーロード．
 *
 * @return 結果のVector3．
 */
Vector3  Vector3::operator + () const
{
	return *this;
}


/*===========================================================================*/
/**
 * (-)単項演算子オーバーロード．
 *
 * @return 結果のVector3.
 */
Vector3  Vector3::operator - () const
{
	return Vector3( -x, -y, -z );
}

/*===========================================================================*/
/**
 * (+=) 演算子オーバーロード．
 * 
 * @param [in]  v Vector3．
 * @return 結果のVector3．
 */
Vector3&  Vector3::operator += ( const Vector3& v )
{
	x = x + v.x;
	y = y + v.y;
	z = z + v.z;

	return *this;
}

/*===========================================================================*/
/**
 * (-=) 演算子オーバーロード．
 * 
 * @param [in]  v Vector3．
 * @return 結果のVector3．
 */
Vector3&  Vector3::operator -= ( const Vector3& v )
{
	x = x - v.x;
	y = y - v.y;
	z = z - v.z;

	return *this;
}

/*===========================================================================*/
/**
 * (*=) 演算子オーバーロード．
 * 
 * @param [in]  v Vector3．
 * @return 結果のVector3．
 */
Vector3&  Vector3::operator *= ( const Vector3& v )
{
	x = x * v.x;
	y = y * v.y;
	z = z * v.z;

	return *this;
}

/*===========================================================================*/
/**
 * (/=) 演算子オーバーロード．
 * 
 * @param [in]  v Vector3．
 * @return 結果のVector3．
 */
Vector3&  Vector3::operator /= ( const Vector3& v )
{
	x = x / v.x;
	y = y / v.y;
	z = z / v.z;

	return *this;
}

/*===========================================================================*/
/**
 * (*=) 演算子オーバーロード．
 * 
 * @param [in]  s スカラー．
 * @return 結果のVector3．
 */
Vector3& Vector3::operator *= ( float s )
{
	x = x * s;
	y = y * s;
	z = z * s;

	return *this;
}

/*===========================================================================*/
/**
 * (/=) 演算子オーバーロード．
 * 
 * @param [in]  s スカラー．
 * @return 結果のVector3．
 */
Vector3& Vector3::operator /= ( float s )
{
	x = x / s;
	y = y / s;
	z = z / s;

	return *this;
}

/***  以下非メンバ関数 *******************************************************/

/*===========================================================================*/
/**
 * (+)演算子オーバーロード．
 * 
 * @param [in]  v1 Vector3．
 * @param [in]  v2 Vector3．
 * @return 結果のVector3．
 */
const Vector3 operator + ( const Vector3& v1, const Vector3& v2 )
{
	Vector3 result( v1 );

	result += v2;

	return result;
}

/*===========================================================================*/
/**
 * (-)演算子オーバーロード．
 * 
 * @param [in]  v1 Vector3．
 * @param [in]  v2 Vector3．
 * @return 結果のVector3．
 */
const Vector3 operator - ( const Vector3& v1, const Vector3& v2 )
{
	Vector3 result( v1 );

	result -= v2;

	return result;
}

/*===========================================================================*/
/**
 * (*)演算子オーバーロード．
 * 
 * @param [in]  v1 Vector3．
 * @param [in]  v2 Vector3．
 * @return 結果のVector3．
 */
const Vector3 operator * ( const Vector3& v1, const Vector3& v2 )
{
	Vector3 result( v1 );

	result *= v2;

	return result;
}

/*===========================================================================*/
/**
 * (*)演算子オーバーロード．
 * 
 * @param [in]  v Vector3．
 * @param [in]  s スカラー．
 * @return 結果のVector3．
 */
const Vector3 operator * ( const Vector3& v, const float s )
{
	Vector3 result( v );

	result *= s;

	return result;
}

/*===========================================================================*/
/**
 * (*)演算子オーバーロード．
 * 
 * @param [in]  s スカラー．
 * @param [in]  v Vector3．
 * @return 結果のVector3．
 */
const Vector3 operator * ( const float s, const Vector3& v )
{
	return v * s;
}

/*===========================================================================*/
/**
 * (*)演算子オーバーロード(座標変換)．
 * 
 * @param [in]  m Matrix4．
 * @param [in]  v Vector3．
 * @return 結果のVector3．
 */
const Vector3 operator * ( const Matrix4& m, const Vector3& v )
{
	float x = v.x * m.m[0][0] + v.y * m.m[1][0] + v.z * m.m[2][0] + m.m[3][0];
	float y = v.x * m.m[0][1] + v.y * m.m[1][1] + v.z * m.m[2][1] + m.m[3][1];
	float z = v.x * m.m[0][2] + v.y * m.m[1][2] + v.z * m.m[2][2] + m.m[3][2];
	float w = v.x * m.m[0][3] + v.y * m.m[1][3] + v.z * m.m[2][3] + m.m[3][3];

	return Vector3( x / w, y / w, z / w );
}

/*===========================================================================*/
/**
 * (*)演算子オーバーロード(座標変換)．
 * 
 * @param [in]  v Vector3．
 * @param [in]  m Matrix4．
 * @return 結果のVector3．
 */
const Vector3 operator * ( const Vector3& v, const Matrix4& m )
{
	float x = v.x * m.m[0][0] + v.y * m.m[0][1] + v.z * m.m[0][2] + m.m[0][3];
	float y = v.x * m.m[1][0] + v.y * m.m[1][1] + v.z * m.m[1][2] + m.m[1][3];
	float z = v.x * m.m[2][0] + v.y * m.m[2][1] + v.z * m.m[2][2] + m.m[2][3];
	float w = v.x * m.m[3][0] + v.y * m.m[3][1] + v.z * m.m[3][2] + m.m[3][3];

	return Vector3( x / w, y / w, z / w );
}

/*===========================================================================*/
/**
 * (/)演算子オーバーロード．
 * 
 * @param [in]  v1 Vector3．
 * @param [in]  v2 Vector3．
 * @return 結果のVector3．
 */
const Vector3 operator / ( const Vector3& v1, const Vector3& v2 )
{
	Vector3 result( v1 );

	result /= v2;

	return result;
}

/*===========================================================================*/
/**
 * (/)演算子オーバーロード．
 * 
 * @param [in]  v Vector3．
 * @param [in]  s スカラー．
 * @return 結果のVector3．
 */
const Vector3 operator / ( const Vector3& v, float s )
{
	Vector3 result( v );

	result /= s;

	return result;
}

/*===========================================================================*/
/**
 * (/)演算子オーバーロード．
 * 
 * @param [in]  s スカラー．
 * @param [in]  v Vector3．
 * @return 結果のVector3．
 */
const Vector3 operator / ( float s, const Vector3& v )
{
	return v / s;
}

/*===========================================================================*/
/**
 * (==) 演算子オーバーロード．
 * 
 * @param [in]  v1 Vector3．
 * @param [in]  v2 Vector3．
 * @return 比較結果．
 */
bool operator == ( const Vector3& v1, const Vector3& v2 )
{
	return ( v1.x == v2.x && v1.y == v2.y && v1.z == v2.z );
}

/*===========================================================================*/
/**
 * (!=) 演算子オーバーロード．
 * 
 * @param [in]  v1 Vector3．
 * @param [in]  v2 Vector3．
 * @return 比較結果．
 */
bool operator != ( const Vector3& v1, const Vector3& v2 )
{
	return !( v1 == v2 );
}

/*===========================================================================*/
/**
 * (<) 演算子オーバーロード．
 * 
 * @param [in]  v1 Vector3．
 * @param [in]  v2 Vector3．
 * @return 比較結果．
 */
bool operator < ( const Vector3& v1, const Vector3& v2 )
{
	if( v1.x <= v2.x ){
		return false;
	} 
	if( v1.y <= v2.y ){
		return false;
	}
	if( v1.z <= v2.z ){
		return false;
	}

	return true;
}

/*===========================================================================*/
/**
 * (>) 演算子オーバーロード．
 * 
 * @param [in]  v1 Vector3．
 * @param [in]  v2 Vector3．
 * @return 比較結果．
 */
bool operator > ( const Vector3& v1, const Vector3& v2 )
{
	if ( v1.x <= v2.x )
	{
		return false;
	}
	if ( v1.y <= v2.y )
	{
		return false;
	}
	if ( v1.z <= v2.z )
	{
		return false;
	}

	return	true;
}

/*===========================================================================*/
/**
 * (<=) 演算子オーバーロード．
 * 
 * @param [in]  v1 Vector3．
 * @param [in]  v2 Vector3．
 * @return 比較結果．
 */
bool operator <= ( const Vector3& v1, const Vector3& v2 )
{
	if( v1.x < v2.x ){
		return false;
	} 
	if( v1.y < v2.y ){
		return false;
	}
	if( v1.z < v2.z ){
		return false;
	}

	return true;
}

/*===========================================================================*/
/**
 * (>=) 演算子オーバーロード．
 * 
 * @param [in]  v1 Vector3．
 * @param [in]  v2 Vector3．
 * @return 比較結果．
 */
bool operator >= ( const Vector3& v1, const Vector3& v2 )
{
	if ( v1.x < v2.x )
	{
		return false;
	}
	if ( v1.y < v2.y )
	{
		return false;
	}
	if ( v1.z < v2.z )
	{
		return false;
	}

	return	true;
}

} // namespace tglib

/*========= End of File =====================================================*/
